package com.spsoft.vatoutinv.service.matchflow.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.listener.ExcelListener;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.ExcelUtils;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.entity.NvatOutInvoiceDetails;
import com.spsoft.system.entity.NvatOutInvoiceItems;
import com.spsoft.system.entity.NvatRevmapinvoitems;
import com.spsoft.system.entity.NvatTrandtadvaltaxsep;
import com.spsoft.system.mapper.NvatOutInvoiceItemsMapper;
import com.spsoft.system.mapper.NvatRevmapinvoitemsMapper;
import com.spsoft.system.service.SequenceService;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.constants.DictConstant;
import com.spsoft.vatoutinv.entity.matchflow.VmsMatching;
import com.spsoft.vatoutinv.entity.matchflow.VmsMatchingDetail;
import com.spsoft.vatoutinv.entity.matchflow.excel.MatchBdhmExcel;
import com.spsoft.vatoutinv.entity.matchflow.excel.MatchBdlxExcel;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceDetails;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.mapper.VatNvatOutInvoiceDetailsMapper;
import com.spsoft.vatoutinv.mapper.VmsNvatTrandtadvaltaxsepMapper;
import com.spsoft.vatoutinv.model.dto.matchflow.*;
import com.spsoft.vatoutinv.model.vo.matchflow.*;
import com.spsoft.vatoutinv.model.vo.matchflow.excel.VmsMatchFlowExcelVo;
import com.spsoft.vatoutinv.model.vo.vmstransactionflowinvoice.VmsTransacitonFlowInvoiceItemVo;
import com.spsoft.vatoutinv.model.vo.vmstransactionflowinvoice.VmsTransactionFlowInvoicePageVo;
import com.spsoft.vatoutinv.service.matchflow.VmsMatchFlowService;
import com.spsoft.vatoutinv.service.matchflow.VmsMatchingDetailService;
import com.spsoft.vatoutinv.service.matchflow.VmsMatchingService;
import com.spsoft.vatoutinv.service.translate.impl.DictTranslate;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.VmsFullOutInvoiceDetailsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 手工匹配流水 服务实现类
 *
 * @author : chenxudong
 * @date : 2024/6/25 11:08
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmsMatchFlowServiceImpl implements VmsMatchFlowService {

    public static final String LOG_MSG = "(手工匹配流水实现层)";

    private final DictTranslate dictTranslate;

    private final SequenceService sequenceService;

    private final VmsMatchingService vmsMatchingService;

    private final VmsMatchingDetailService vmsMatchingDetailService;

    private final VatNvatOutInvoiceDetailsMapper nvatOutInvoiceDetailsMapper;

    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;

    private final VmsNvatTrandtadvaltaxsepMapper vmsNvatTrandtadvaltaxsepMapper;

    private final NvatRevmapinvoitemsMapper nvatRevmapinvoitemsMapper;

    private final VmsFullOutInvoiceDetailsService vmsFullOutInvoiceDetailsService;

    @Override
    public Result<IPage<VmsMatchFlowApplyVo>> pageApply(VmsMatchFlowPageDto pageDto) {
        // 创建分页对象
        Page<VmsMatchFlowApplyVo> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        // 交易机构下拉框处理
        String deptCode = pageDto.getDeptCode();
        if (StringUtils.isNotBlank(deptCode)) {
            List<String> deptCodeList = Arrays.asList(deptCode.split(","));
            pageDto.setDeptCodeList(deptCodeList);
        } else {
            pageDto.setDeptCodeList(Collections.singletonList(SecurityUtils.getDeptCode()));
        }
        // 匹配日期处理 将yyyy-MM-dd转为yyyy-mm-dd hh24:mi:ss
        if (StringUtils.isNotBlank(pageDto.getPprqq()) && StringUtils.isNotBlank(pageDto.getPprqz())) {
            pageDto.setPprqq(DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getPprqq())), CommonConstant.DATE_FORMAT_14));
            pageDto.setPprqz(DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getPprqz())), CommonConstant.DATE_FORMAT_14));
        }
        // 获取手工匹配流水记录
        IPage<VmsMatchFlowApplyVo> matchFlowList = vmsMatchingService.pageApply(page, pageDto);
        return Result.OK(matchFlowList);
    }

    @Override
    public void export(VmsMatchFlowPageDto pageDto, HttpServletResponse response) {
        try {
            // 交易机构下拉框处理
            String deptCode = pageDto.getDeptCode();
            if (StringUtils.isNotBlank(deptCode)) {
                List<String> deptCodeList = Arrays.asList(deptCode.split(","));
                pageDto.setDeptCodeList(deptCodeList);
            } else {
                pageDto.setDeptCodeList(Collections.singletonList(SecurityUtils.getDeptCode()));
            }
            // 匹配日期处理 将yyyy-MM-dd转为yyyy-mm-dd hh24:mi:ss
            if (StringUtils.isNotBlank(pageDto.getPprqq()) && StringUtils.isNotBlank(pageDto.getPprqz())) {
                pageDto.setPprqq(DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getPprqq())), CommonConstant.DATE_FORMAT_14));
                pageDto.setPprqz(DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getPprqz())), CommonConstant.DATE_FORMAT_14));
            }
            // 获取手工匹配流水记录，不分页
            List<VmsMatchFlowApplyVo> matchFlowList = vmsMatchingService.getApplyData(pageDto);
            if (CollectionUtil.isEmpty(matchFlowList)) {
                throw new BusinessException(ResponseEnum.DATA_NOT_FIND_ERROR);
            }
            // 数据转换
            List<VmsMatchFlowExcelVo> excelVoList = BeanUtils.copyListProperties(matchFlowList, VmsMatchFlowExcelVo::new, (s, t) -> {
                // 导出时需要将字典值转换
                t.setFplx(dictTranslate.translate(DictConstant.VMS_FPLX, s.getFplx()));
                t.setKprq(DateUtil.format(s.getKprq(), CommonConstant.DATE_FORMAT_8));
            });
            // 添加序号
            for (int i = 0; i < excelVoList.size(); i++) {
                excelVoList.get(i).setXh(i + 1);
            }

            // excel导出到指定模板中
            String rootPath = "export/matchFlowApplyTemplate.xlsx";
            InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(rootPath);
            if (fis == null) {
                log.error("{}模板下载异常,读取不到文件", LOG_MSG);
                throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_TEMPLATE_ERROR);
            }
            // 导出
            ExcelUtils.exportExcelWithTemplate(excelVoList, "发票匹配流水申请记录", response, fis);
        } catch (Exception e) {
            log.error("{}导出excel出现异常", LOG_MSG, e);
        }
    }

    @Override
    public Result<IPage<VmsMatchInvoicePageVo>> pageInvoice(VmsMatchInvoicePageDto pageDto) {
        // 创建分页对象
        Page<VmsMatchFlowApplyVo> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        // 开票日期处理 将yyyy-MM-dd转为yyyy-mm-dd hh24:mi:ss
        if (StringUtils.isNotBlank(pageDto.getKprqq()) && StringUtils.isNotBlank(pageDto.getKprqz())) {
            pageDto.setKprqq(DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getKprqq())), CommonConstant.DATE_FORMAT_14));
            pageDto.setKprqz(DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getKprqz())), CommonConstant.DATE_FORMAT_14));
        }
        // 查询可以匹配流水的发票信息
        IPage<VmsMatchInvoicePageVo> matchInvoicePageList = nvatOutInvoiceDetailsMapper.pageMatchInvoice(page, pageDto);
        return Result.OK(matchInvoicePageList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<VmsMatchInvoiceInfoVo> fastAdd(String fpdm, String fphm, Long applyId, TokenUser tokenUser) {
        if (StringUtils.isBlank(fphm)) {
            return Result.ERROR(ResponseEnum.FPHM_EMPTY_ERROR);
        }
        if (ObjectUtil.isEmpty(applyId)) {
            return Result.ERROR(ResponseEnum.APPLY_ID_EMPTY_ERROR);
        }

        // 查询老系统发票信息
        LambdaQueryWrapper<NvatOutInvoiceDetails> invoiceQuery = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(fpdm)) {
            invoiceQuery.eq(NvatOutInvoiceDetails::getFpdm, fpdm);
        }
        invoiceQuery.eq(NvatOutInvoiceDetails::getFphm, fphm);
        invoiceQuery.eq(NvatOutInvoiceDetails::getQydjid, tokenUser.getDeptCode());
        NvatOutInvoiceDetails nvatOutInvoiceDetail = nvatOutInvoiceDetailsMapper.selectOne(invoiceQuery);
        if (nvatOutInvoiceDetail == null) {
            return Result.ERROR(ResponseEnum.INVOICE_NOT_FOUND);
        }

        // 校验匹配状态
        if (!CommonEnum.MATCHING_STATUS_0.getKey().equals(nvatOutInvoiceDetail.getPpzt())) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_PPZT_ERROR);
        }

        // 判断发票匹配流水申请是否存在未结束的流程
        Result<Object> result = vmsMatchingService.judgeProcessIsFinish(CommonEnum.MATCH_FLOW_TYPE_0.getKey(),
                fpdm, fphm, tokenUser.getDeptCode(), applyId, nvatOutInvoiceDetail.getOidid());
        if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            return Result.ERRORT(result.getCode(), result.getMessage());
        }

        // 判断数据来源
        if (!StrUtil.equalsAny(StringUtil.toString(nvatOutInvoiceDetail.getSjly()), CommonEnum.DATA_SOURCE_1.getKey(),
                CommonEnum.DATA_SOURCE_99.getKey())) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_SJLY_ERROR);
        }

        // 判断发票状态
        if (CommonEnum.INVOICE_STATUS_2.getKey().equals(StringUtil.toString(nvatOutInvoiceDetail.getFpzt()))) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_FPZT_ERROR);
        }

        // 判断开票状态
        if (!StrUtil.equalsAny(StringUtil.toString(nvatOutInvoiceDetail.getKpzt()), CommonConstant.STR_2, CommonConstant.STR_4)) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_KPZT_ERROR);
        }

        // 查询发票明细信息
        LambdaQueryWrapper<NvatOutInvoiceItems> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(NvatOutInvoiceItems::getOidid, nvatOutInvoiceDetail.getOidid());
        itemQuery.orderByAsc(NvatOutInvoiceItems::getIviid);
        List<NvatOutInvoiceItems> nvatOutInvoiceItemList = nvatOutInvoiceItemsMapper.selectList(itemQuery);

        // 将快速添加的数据保存在手工匹配流水表和明细表中
        Long matid = saveMatchData(applyId, tokenUser, nvatOutInvoiceDetail);

        // 实体类转换
        VmsMatchInvoiceDetailVo invoiceDetailVo = vmsMatchingService.convertToDetailVo(nvatOutInvoiceDetail, matid);
        List<VmsMatchInvoiceItemVo> invoiceItemVoList = BeanUtils.copyListProperties(nvatOutInvoiceItemList, VmsMatchInvoiceItemVo::new);

        // 构建返回数据
        VmsMatchInvoiceInfoVo invoiceInfoVo = new VmsMatchInvoiceInfoVo();
        invoiceInfoVo.setInvoiceDetail(invoiceDetailVo);
        invoiceInfoVo.setInvoiceItemList(invoiceItemVoList);

        return Result.OK(invoiceInfoVo);
    }

    /**
     * 将快速添加的数据保存在手工匹配流水表和明细表中
     * @param applyId 审批流id
     * @param tokenUser 登录用户信息
     * @param nvatOutInvoiceDetail 老系统发票主信息
     */
    private Long saveMatchData(Long applyId, TokenUser tokenUser, NvatOutInvoiceDetails nvatOutInvoiceDetail) {
        LambdaQueryWrapper<VmsMatching> query1 = new LambdaQueryWrapper<>();
        query1.eq(VmsMatching::getApplyId, applyId);
        VmsMatching vmsMatching = vmsMatchingService.getOne(query1);
        if (vmsMatching != null) {
            // 删除手工匹配流水信息
            vmsMatchingService.remove(query1);
            // 删除手工匹配流水明细信息
            LambdaQueryWrapper<VmsMatchingDetail> query2 = new LambdaQueryWrapper<>();
            query2.eq(VmsMatchingDetail::getMatid, vmsMatching.getMatid());
            vmsMatchingDetailService.remove(query2);
        }

        // 保存手工匹配流水信息
        VmsMatching vmsMatch = new VmsMatching();
        vmsMatch.setApplyId(applyId);
        vmsMatch.setApplyType(CommonEnum.MATCH_FLOW_TYPE_0.getKey());
        vmsMatch.setFplx(nvatOutInvoiceDetail.getFplxdm());
        vmsMatch.setFpdm(nvatOutInvoiceDetail.getFpdm());
        vmsMatch.setFphm(nvatOutInvoiceDetail.getFphm());
        vmsMatch.setFpje(nvatOutInvoiceDetail.getJshj());
        vmsMatch.setFpse(nvatOutInvoiceDetail.getHjse());
        vmsMatch.setOidid(nvatOutInvoiceDetail.getOidid());
        vmsMatch.setDeptCode(tokenUser.getDeptCode());
        vmsMatch.setCreatBy(tokenUser.getUserCode());
        vmsMatch.setCreatTime(new Date());
        vmsMatch.setUpdateBy(tokenUser.getUserCode());
        vmsMatch.setUpdateTime(new Date());
        vmsMatchingService.save(vmsMatch);

        return vmsMatch.getMatid();
    }

    @Override
    public Result<VmsMatchInvoiceInfoVo> getApplyDetail(Long applyId) {
        // 查询手工匹配流水信息
        LambdaQueryWrapper<VmsMatching> query = new LambdaQueryWrapper<>();
        query.eq(VmsMatching::getApplyId, applyId);
        VmsMatching vmsMatching = vmsMatchingService.getOne(query);
        if (vmsMatching == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        VmsMatchAllowErrorVo matchAllowErrorVo = new VmsMatchAllowErrorVo();
        matchAllowErrorVo.setYxcyje(vmsMatching.getYxcyje());
        matchAllowErrorVo.setCyjesm(vmsMatching.getCyjesm());
        // 计算当前匹配差异金额
        if (ObjectUtil.isNotEmpty(vmsMatching.getFpje()) && ObjectUtil.isNotEmpty(vmsMatching.getLsje())) {
            BigDecimal dqppcyje = vmsMatching.getFpje().subtract(vmsMatching.getLsje());
            matchAllowErrorVo.setDqppcyje(dqppcyje);
        }

        // 查询老系统发票信息
        LambdaQueryWrapper<NvatOutInvoiceDetails> invoiceQuery = new LambdaQueryWrapper<>();
        invoiceQuery.eq(NvatOutInvoiceDetails::getOidid, vmsMatching.getOidid());
        NvatOutInvoiceDetails nvatOutInvoiceDetail = nvatOutInvoiceDetailsMapper.selectOne(invoiceQuery);
        if (nvatOutInvoiceDetail == null) {
            return Result.ERROR(ResponseEnum.INVOICE_NOT_FOUND);
        }

        // 查询发票明细信息
        LambdaQueryWrapper<NvatOutInvoiceItems> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(NvatOutInvoiceItems::getOidid, nvatOutInvoiceDetail.getOidid());
        itemQuery.orderByAsc(NvatOutInvoiceItems::getIviid);
        List<NvatOutInvoiceItems> nvatOutInvoiceItemList = nvatOutInvoiceItemsMapper.selectList(itemQuery);

        // 实体类转换
        VmsMatchInvoiceDetailVo invoiceDetailVo = vmsMatchingService.convertToDetailVo(nvatOutInvoiceDetail, vmsMatching.getMatid());
        List<VmsMatchInvoiceItemVo> invoiceItemVoList = BeanUtils.copyListProperties(nvatOutInvoiceItemList, VmsMatchInvoiceItemVo::new);

        // 构造返回数据
        VmsMatchInvoiceInfoVo vmsMatchInvoiceInfoVo = new VmsMatchInvoiceInfoVo();
        vmsMatchInvoiceInfoVo.setMatchAllowError(matchAllowErrorVo);
        vmsMatchInvoiceInfoVo.setInvoiceDetail(invoiceDetailVo);
        vmsMatchInvoiceInfoVo.setInvoiceItemList(invoiceItemVoList);

        return Result.OK(vmsMatchInvoiceInfoVo);
    }

    @Override
    public Result<VmsMatchRecordVo> getMatchDetail(Long matid) {
        // 查询手工匹配流水主信息
        VmsMatchRecordVo vmsMatchRecordVo = vmsMatchingService.getMatchDetailById(matid);
        if (vmsMatchRecordVo == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        // 查询发票明细信息
        LambdaQueryWrapper<NvatOutInvoiceItems> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(NvatOutInvoiceItems::getOidid, vmsMatchRecordVo.getOidid());
        itemQuery.orderByAsc(NvatOutInvoiceItems::getIviid);
        List<NvatOutInvoiceItems> nvatOutInvoiceItemList = nvatOutInvoiceItemsMapper.selectList(itemQuery);

        List<VmsMatchRecordVo.VmsMatchItemRecordVo> vmsMatchItemRecordList = new ArrayList<>();
        for (NvatOutInvoiceItems nvatOutInvoiceItems : nvatOutInvoiceItemList) {
            // 每一条发票明细都查询已匹配的流水
            LambdaQueryWrapper<VmsMatchingDetail> detailQuery = new LambdaQueryWrapper<>();
            detailQuery.eq(VmsMatchingDetail::getMatid, matid);
            detailQuery.eq(VmsMatchingDetail::getIviid, nvatOutInvoiceItems.getIviid());
            detailQuery.orderByAsc(VmsMatchingDetail::getMatdeid);
            List<VmsMatchingDetail> matchDetailList = vmsMatchingDetailService.list(detailQuery);
            VmsMatchRecordVo.VmsMatchItemRecordVo vmsMatchItemRecordVo = vmsMatchingService.buildMatchItemRecord(nvatOutInvoiceItems, matchDetailList);

            vmsMatchItemRecordList.add(vmsMatchItemRecordVo);
        }

        vmsMatchRecordVo.setMatchItemRecordList(vmsMatchItemRecordList);
        return Result.OK(vmsMatchRecordVo);
    }

    @Override
    public Result<IPage<VmsTransactionFlowInvoicePageVo>> queryFlowByItem(VmsItemFlowPageDto pageDto) {
        // 查询手工匹配流水信息
        LambdaQueryWrapper<VmsMatching> query = new LambdaQueryWrapper<>();
        query.eq(VmsMatching::getMatid, pageDto.getMatid());
        query.eq(VmsMatching::getDeptCode, pageDto.getDeptCode());
        VmsMatching vmsMatching = vmsMatchingService.getOne(query);
        if (vmsMatching == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        // 根据发票明细查询已匹配的交易流水
        Page<VmsTransactionFlowInvoicePageVo> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        IPage<VmsTransactionFlowInvoicePageVo> pageVoIPage = vmsMatchingDetailService.queryFlowByItem(page, vmsMatching.getMatid(), pageDto.getIviid());
        return Result.OK(pageVoIPage);
    }

    @Override
    public Result<IPage<VmsTransactionFlowInvoicePageVo>> queryFlowByAutoOrHand(VmsQueryMatchFlowPageDto pageDto) {
        // 匹配流水查询时，业务编号不能为空
        if (CommonConstant.STR_0.equals(pageDto.getCxlx())
            && StringUtils.isBlank(pageDto.getYwbh())) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_YWBH_EMPTY_ERROR);
        }
        Page<VmsTransactionFlowInvoicePageVo> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        // 匹配流水/手工匹配-分页查询可匹配流水
        IPage<VmsTransactionFlowInvoicePageVo> flowInvoicePageVoIPage = vmsNvatTrandtadvaltaxsepMapper.queryFlowByAutoOrHand(page, pageDto);
        return Result.OK(flowInvoicePageVoIPage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> itemMatchFlow(VmsItemMatchFlowDto dto, TokenUser tokenUser) {
        // 查询手工匹配流水信息
        LambdaQueryWrapper<VmsMatching> query = new LambdaQueryWrapper<>();
        query.eq(VmsMatching::getApplyId, dto.getApplyId());
        VmsMatching vmsMatching = vmsMatchingService.getOne(query);
        if (vmsMatching == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        // 匹配流水
        if (CommonConstant.STR_0.equals(dto.getCzlx())) {
            LambdaQueryWrapper<VmsMatchingDetail> detailQuery = new LambdaQueryWrapper<>();
            detailQuery.eq(VmsMatchingDetail::getMatid, vmsMatching.getMatid());
            detailQuery.eq(VmsMatchingDetail::getIviid, dto.getIviid());
            detailQuery.orderByAsc(VmsMatchingDetail::getMatdeid);
            List<VmsMatchingDetail> matchDetailList = vmsMatchingDetailService.list(detailQuery);
            if (CollectionUtil.isNotEmpty(matchDetailList)) {
                // 判断所选的流水是否已经匹配
                List<Long> rdidList = matchDetailList.stream().map(VmsMatchingDetail::getRdid).collect(Collectors.toList());
                for (Long rdid : dto.getRdidList()) {
                    if (rdidList.contains(rdid)) {
                        return Result.ERROR(ResponseEnum.MATCH_FLOW_RDID_ERROR);
                    }
                }
            }
            // 查询当前匹配的发票明细信息
            LambdaQueryWrapper<NvatOutInvoiceItems> itemQuery = new LambdaQueryWrapper<>();
            itemQuery.eq(NvatOutInvoiceItems::getIviid, dto.getIviid());
            NvatOutInvoiceItems nvatOutInvoiceItem = nvatOutInvoiceItemsMapper.selectOne(itemQuery);

            // 查询当前匹配的流水信息
            List<VmsTransacitonFlowInvoiceItemVo> rdidInfoList = vmsNvatTrandtadvaltaxsepMapper.selectInvoiceByIds(dto.getRdidList());

            // 判断发票税率和流水税率是否一致
            for (VmsTransacitonFlowInvoiceItemVo rdidInfo : rdidInfoList) {
                if (rdidInfo.getSysl().compareTo(nvatOutInvoiceItem.getSl()) != 0) {
                    return Result.ERROR(ResponseEnum.MATCH_FLOW_SLV_ERROR);
                }
            }

            // 流水金额、税额总和
            BigDecimal lsjeTotal = BigDecimal.ZERO, lsseTotal = BigDecimal.ZERO;
            // 插入手工匹配流水详细记录
            List<VmsMatchingDetail> vmsMatchingDetailList = new ArrayList<>();
            for (VmsTransacitonFlowInvoiceItemVo rdidInfo : rdidInfoList) {
                VmsMatchingDetail vmsMatchingDetail = new VmsMatchingDetail();
                vmsMatchingDetail.setMatid(vmsMatching.getMatid());
                vmsMatchingDetail.setOidid(vmsMatching.getOidid());
                vmsMatchingDetail.setIviid(nvatOutInvoiceItem.getIviid());
                vmsMatchingDetail.setRdid(rdidInfo.getId());
                vmsMatchingDetail.setMxje(nvatOutInvoiceItem.getHsje());
                vmsMatchingDetail.setMxse(nvatOutInvoiceItem.getSe());
                vmsMatchingDetail.setMxsl(nvatOutInvoiceItem.getSl());
                vmsMatchingDetail.setLsje(rdidInfo.getBhsje().add(rdidInfo.getXxse()));
                vmsMatchingDetail.setLsse(rdidInfo.getXxse());
                vmsMatchingDetail.setLssl(rdidInfo.getSysl());

                lsjeTotal = lsjeTotal.add(rdidInfo.getBhsje().add(rdidInfo.getXxse()));
                lsseTotal = lsseTotal.add(rdidInfo.getXxse());
                vmsMatchingDetailList.add(vmsMatchingDetail);
            }
            vmsMatchingDetailService.saveBatch(vmsMatchingDetailList);

            // 更新手工匹配流水表中的流水金额、税额总和
            LambdaUpdateWrapper<VmsMatching> updateWrapper = new LambdaUpdateWrapper<>();
            if (ObjectUtil.isNotEmpty(vmsMatching.getLsje())) {
                lsjeTotal = vmsMatching.getLsje().add(lsjeTotal);
            }
            if (ObjectUtil.isNotEmpty(vmsMatching.getLsse())) {
                lsseTotal = vmsMatching.getLsse().add(lsseTotal);
            }
            updateWrapper.set(VmsMatching::getLsje, lsjeTotal);
            updateWrapper.set(VmsMatching::getLsse, lsseTotal);
            updateWrapper.set(VmsMatching::getUpdateBy, tokenUser.getUserCode());
            updateWrapper.set(VmsMatching::getUpdateTime, new Date());
            updateWrapper.eq(VmsMatching::getMatid, vmsMatching.getMatid());
            vmsMatchingService.update(updateWrapper);
        } else {
            // 流水金额、税额总和
            BigDecimal lsjeTotal = BigDecimal.ZERO, lsseTotal = BigDecimal.ZERO;
            // 撤销匹配流水，删除手工匹配流水详细记录
            for (Long rdid : dto.getRdidList()) {
                LambdaQueryWrapper<VmsMatchingDetail> detailQuery = new LambdaQueryWrapper<>();
                detailQuery.eq(VmsMatchingDetail::getMatid, vmsMatching.getMatid());
                detailQuery.eq(VmsMatchingDetail::getRdid, rdid);
                VmsMatchingDetail vmsMatchingDetail = vmsMatchingDetailService.getOne(detailQuery);

                lsjeTotal = lsjeTotal.add(vmsMatchingDetail.getLsje());
                lsseTotal = lsseTotal.add(vmsMatchingDetail.getLsse());

                vmsMatchingDetailService.removeById(vmsMatchingDetail.getMatdeid());
            }

            // 更新手工匹配流水表中的流水金额、税额总和
            LambdaUpdateWrapper<VmsMatching> updateWrapper = new LambdaUpdateWrapper<>();
            if (ObjectUtil.isNotEmpty(vmsMatching.getLsje())) {
                lsjeTotal = vmsMatching.getLsje().subtract(lsjeTotal);
            }
            if (ObjectUtil.isNotEmpty(vmsMatching.getLsse())) {
                lsseTotal = vmsMatching.getLsse().subtract(lsseTotal);
            }
            updateWrapper.set(VmsMatching::getLsje, lsjeTotal);
            updateWrapper.set(VmsMatching::getLsse, lsseTotal);
            updateWrapper.set(VmsMatching::getUpdateBy, tokenUser.getUserCode());
            updateWrapper.set(VmsMatching::getUpdateTime, new Date());
            updateWrapper.eq(VmsMatching::getMatid, vmsMatching.getMatid());
            vmsMatchingService.update(updateWrapper);
        }

        return Result.OK();
    }

    @Override
    public Result<List<VmsTransactionFlowInvoicePageVo>> readExcel(MultipartFile file) {
        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
            byte[] bytes = cloneInputStream(inputStream);

            // 读取保单类型
            ExcelListener<MatchBdlxExcel> excelListener1 = new ExcelListener<>();
            InputStream inputStream1 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream1, MatchBdlxExcel.class, excelListener1).headRowNumber(3).sheet(0).doRead();
            // 获取保单类型
            List<MatchBdlxExcel> bdlxList = excelListener1.getRows();
            if (CollectionUtil.isEmpty(bdlxList)) {
                return Result.ERROR(ResponseEnum.EXCEL_BDLX_EMPTY_ERROR);
            }
            // 保单类型只能为：1：保单号/保全号/定期结算号，2：投保单号，3：学平险受理号，4：汇交单号
            String bdlx = bdlxList.get(0).getBdlx();
            if (!StrUtil.equalsAny(bdlx, CommonConstant.STR_1, CommonConstant.STR_2, CommonConstant.STR_3, CommonConstant.STR_4)) {
                return Result.ERROR(ResponseEnum.EXCEL_BDLX_ILLEGAL_ERROR);
            }

            // 读取保单号码
            ExcelListener<MatchBdhmExcel> excelListener2 = new ExcelListener<>();
            InputStream inputStream2 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream2, MatchBdhmExcel.class, excelListener2).headRowNumber(3).sheet(1).doRead();
            // 获取保单号码信息
            List<MatchBdhmExcel> bdhmExcelList = excelListener2.getRows();
            if (CollectionUtil.isEmpty(bdhmExcelList)) {
                return Result.ERROR(ResponseEnum.EXCEL_BDHM_EMPTY_ERROR);
            }
            List<String> bdhmList = bdhmExcelList.stream().map(MatchBdhmExcel::getBdhm).collect(Collectors.toList());
            if (bdhmList.size() > 1000) {
                return Result.ERROR(ResponseEnum.EXCEL_BDHM_MAX_ERROR);
            }
            // 查询数据库
            List<VmsTransactionFlowInvoicePageVo> flowList = vmsNvatTrandtadvaltaxsepMapper.queryMatchFlowByExcel(bdlx, bdhmList);
            return Result.OK(flowList);
        } catch (BusinessException e) {
            log.error("{}手工匹配-导入查询出现异常，code：{}，msg：{}", LOG_MSG, e.getCode(), e.getMsg());
            throw new BusinessException(e.getCode(), e.getMsg());
        } catch (Exception e) {
            log.error("{}手工匹配-导入查询出现未知异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_READ_ERROR);
        }
    }

    /**
     * 克隆InputStream
     */
    private static byte[] cloneInputStream(InputStream input) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            baos.close();
            input.close();
            return baos.toByteArray();
        } catch (IOException e) {
            log.error("{}克隆InputStream异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_READ_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> matchFlowProcess(Long applyId) {
        /**
         * 审批节点
         * 1、判断当前发票的匹配状态是否为未匹配、明细匹配的流水是否为未开票状态
         * 2、将发票明细和匹配的流水在关联关系表中进行关联
         * 3、将流水的开票状态修改为已开票、发票的匹配状态修改为已匹配、记录匹配时间
         */
        log.info("{}发票匹配流水流程进行匹配，审批流id：{}", LOG_MSG, applyId);
        // 查询手工匹配流水信息
        LambdaQueryWrapper<VmsMatching> query1 = new LambdaQueryWrapper<>();
        query1.eq(VmsMatching::getApplyId, applyId);
        VmsMatching vmsMatching = vmsMatchingService.getOne(query1);
        if (vmsMatching == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        // 查询手工匹配流水详细信息
        LambdaQueryWrapper<VmsMatchingDetail> detailQuery = new LambdaQueryWrapper<>();
        detailQuery.eq(VmsMatchingDetail::getMatid, vmsMatching.getMatid());
        detailQuery.orderByAsc(VmsMatchingDetail::getMatdeid);
        List<VmsMatchingDetail> matchDetailList = vmsMatchingDetailService.list(detailQuery);
        if (CollectionUtil.isEmpty(matchDetailList)) {
            return Result.ERROR(ResponseEnum.ITEM_NOT_MATCH_FLOW_ERROR);
        }

        // 查询老系统发票信息
        LambdaQueryWrapper<NvatOutInvoiceDetails> invoiceQuery = new LambdaQueryWrapper<>();
        invoiceQuery.select(NvatOutInvoiceDetails::getPpzt);
        invoiceQuery.eq(NvatOutInvoiceDetails::getOidid, vmsMatching.getOidid());
        NvatOutInvoiceDetails nvatOutInvoiceDetail = nvatOutInvoiceDetailsMapper.selectOne(invoiceQuery);
        if (nvatOutInvoiceDetail == null) {
            return Result.ERROR(ResponseEnum.INVOICE_NOT_FOUND);
        }
        // 校验发票的匹配状态是否为未匹配
        if (!CommonEnum.MATCHING_STATUS_0.getKey().equals(nvatOutInvoiceDetail.getPpzt())) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_PPZT_ERROR);
        }

        // 校验流水的开票状态是否为未开票
        for (VmsMatchingDetail vmsMatchingDetail : matchDetailList) {
            LambdaQueryWrapper<NvatTrandtadvaltaxsep> query = new LambdaQueryWrapper<>();
            query.select(NvatTrandtadvaltaxsep::getLszt);
            query.eq(NvatTrandtadvaltaxsep::getRdid, vmsMatchingDetail.getRdid());
            NvatTrandtadvaltaxsep nvatTrandtadvaltaxsep = vmsNvatTrandtadvaltaxsepMapper.selectOne(query);
            if (nvatTrandtadvaltaxsep == null || nvatTrandtadvaltaxsep.getLszt() != 1L) {
                return Result.ERROR(ResponseEnum.MATCH_FLOW_LSZT_ERROR);
            }
        }

        for (VmsMatchingDetail vmsMatchingDetail : matchDetailList) {
            // 维护发票明细和流水关联关系
            NvatRevmapinvoitems nvatRevmapinvoitems = new NvatRevmapinvoitems();
            nvatRevmapinvoitems.setNrmivid(sequenceService.getSequence(CommonConstant.NVAT_REVMAPINVOITEMS));
            nvatRevmapinvoitems.setOidid(vmsMatchingDetail.getOidid());
            nvatRevmapinvoitems.setIviid(vmsMatchingDetail.getIviid());
            nvatRevmapinvoitems.setRdid(vmsMatchingDetail.getRdid());
            nvatRevmapinvoitemsMapper.insert(nvatRevmapinvoitems);

            // 将流水状态修改为已开票
            LambdaUpdateWrapper<NvatTrandtadvaltaxsep> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(NvatTrandtadvaltaxsep::getLszt, 3L);
            updateWrapper.set(NvatTrandtadvaltaxsep::getWkpje, BigDecimal.ZERO);
            updateWrapper.eq(NvatTrandtadvaltaxsep::getRdid, vmsMatchingDetail.getRdid());
            vmsNvatTrandtadvaltaxsepMapper.update(null, updateWrapper);
        }

        // 将老系统发票的状态修改为已匹配、记录匹配时间
        LambdaUpdateWrapper<NvatOutInvoiceDetails> updateWrapper2 = new LambdaUpdateWrapper<>();
        updateWrapper2.set(NvatOutInvoiceDetails::getPpzt, CommonEnum.MATCHING_STATUS_1.getKey());
        updateWrapper2.set(NvatOutInvoiceDetails::getExpcol2, DateUtil.format(new Date(), CommonConstant.DATE_FORMAT_8_SHORT));
        updateWrapper2.eq(NvatOutInvoiceDetails::getOidid, vmsMatching.getOidid());
        nvatOutInvoiceDetailsMapper.update(null, updateWrapper2);

        if (StringUtils.isNotBlank(vmsMatching.getFphm()) && vmsMatching.getFphm().length() == 20) {
            // 将数电发票的状态修改为已匹配
            LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper3 = new LambdaUpdateWrapper<>();
            updateWrapper3.set(VmsFullOutInvoiceDetails::getPpzt, CommonEnum.MATCHING_STATUS_1.getKey());
            updateWrapper3.set(VmsFullOutInvoiceDetails::getUpdateBy, SecurityUtils.getUserCode());
            updateWrapper3.set(VmsFullOutInvoiceDetails::getUpdateTime, new Date());
            updateWrapper3.eq(VmsFullOutInvoiceDetails::getFphm, vmsMatching.getFphm());
            vmsFullOutInvoiceDetailsService.update(updateWrapper3);
        }

        return Result.OK();
    }

    @Override
    public Result<Object> saveAllowError(VmsMatchAllowErrorDto dto) {
        // 查询手工匹配流水信息
        LambdaQueryWrapper<VmsMatching> query = new LambdaQueryWrapper<>();
        query.eq(VmsMatching::getApplyId, dto.getApplyId());
        VmsMatching vmsMatching = vmsMatchingService.getOne(query);
        if (vmsMatching == null) {
            return Result.ERROR(ResponseEnum.MATCH_FLOW_NOT_FIND_ERROR);
        }

        // 当前匹配差异金额为0时，允许差异金额和差异金额说明可以为空，此时允许差异金额默认为0
        if (ObjectUtil.isEmpty(dto.getYxcyje())) {
            dto.setYxcyje(BigDecimal.ZERO);
        }
        if (StringUtils.isBlank(dto.getCyjesm())) {
            dto.setCyjesm(StringUtils.EMPTY);
        }

        // 更新允许差异金额、差异金额说明
        LambdaUpdateWrapper<VmsMatching> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(VmsMatching::getYxcyje, dto.getYxcyje());
        updateWrapper.set(VmsMatching::getCyjesm, dto.getCyjesm());
        updateWrapper.eq(VmsMatching::getMatid, vmsMatching.getMatid());
        vmsMatchingService.update(updateWrapper);

        return Result.OK();
    }

}
